#include "./sensor.h"
#include "../device/gpio.h"


namespace driver {

Sensor sensor;

using namespace device;

static void delay() {
    for (volatile uint32_t i = 0; i < 100; i ++);
}

namespace u5a {
using S0 = PC<4>;
using S1 = PC<5>;
using S2 = PC<6>;
using Z = PC<15>;

void select(uint8_t addr) {
    if (addr & 0x01) {
        S0::set();
    } else {
        S0::clr();
    }
    if (addr & 0x02) {
        S1::set();
    } else {
        S1::clr();
    }
    if (addr & 0x04) {
        S2::set();
    } else {
        S2::clr();
    }
}

inline bool read(uint8_t addr) {
    select(addr);
    delay();
    return Z::read();
}

}
namespace u1e_u2e {

using S0 = PC<10>;
using S1 = PC<11>;
using S2 = PC<12>;
using Z1 = PB<14>;
using Z2 = PB<15>;

void select(uint8_t addr) {
    if (addr & 0x01) {
        S0::set();
    } else {
        S0::clr();
    }
    if (addr & 0x02) {
        S1::set();
    } else {
        S1::clr();
    }
    if (addr & 0x04) {
        S2::set();
    } else {
        S2::clr();
    }
}

inline bool read_u1e(uint8_t addr) {
    select(addr);
    delay();
    return Z1::read();
}

inline bool read_u2e(uint8_t addr) {
    select(addr);
    delay();
    return Z2::read();
}

}

using PickSw = PA<6>;
using Raster2 = PA<8>;
using Raster = PA<12>;
using HBI = PC<9>;

void Sensor::init() {

    RCU_APB2EN |= RCU_APB2EN_PCEN |
        RCU_APB2EN_PBEN |
        RCU_APB2EN_PAEN |
        RCU_APB2EN_AFEN;

    config_pp_output<u5a::S0, u5a::S1, u5a::S2,
        u1e_u2e::S0, u1e_u2e::S1, u1e_u2e::S2>();
    
    config_up_input<u5a::Z, 
        u1e_u2e::Z1, 
        u1e_u2e::Z2, 
        PickSw, Raster2,
        HBI,
        Raster>();

    AFIO_EXTISS3 &= ~0x0F;
    AFIO_EXTISS2 &= ~0x0F;

    EXTI_INTEN |= EXTI_INTEN_INTEN12 | EXTI_INTEN_INTEN8;
    EXTI_RTEN |= EXTI_RTEN_RTEN12 | EXTI_RTEN_RTEN8;
    EXTI_PD = EXTI_PD_PD12 | EXTI_PD_PD8;

    NVIC_EnableIRQ(EXTI10_15_IRQn);
 //   NVIC_EnableIRQ(EXTI5_9_IRQn);
}

bool Sensor::is_raster() {
    return !Raster::read();
}

bool Sensor::is_raster2() {
    return !Raster2::read();
}

bool Sensor::is_raster_check() {
    if (is_raster()) {
        return true;
    }
    return m_raster_flag;
}

bool Sensor::read_u5a(uint8_t addr) {
    AUTO_LOCK(m_u5a);
    return u5a::read(addr);
}

bool Sensor::read_u1e(uint8_t addr) {
    AUTO_LOCK(m_u1e_u2e);
    return u1e_u2e::read_u1e(addr);
}

bool Sensor::read_u2e(uint8_t addr) {
    AUTO_LOCK(m_u1e_u2e);
    return u1e_u2e::read_u2e(addr);
}

bool Sensor::is_col_checked(uint8_t col) {
    if (col <= 8) {
        return read_u1e(col - 1);
    }
    return read_u2e(col - 1 - 8);
}


}

extern "C"
void EXTI10_15_IRQHandler() {
    if ((EXTI_PD & EXTI_PD_PD12) != 0) {
        EXTI_PD = EXTI_PD_PD12;
        driver::sensor.set_raster();
    }
}

extern "C"
void EXTI5_9_IRQHandler() {
    if ((EXTI_PD & EXTI_PD_PD8) != 0) {
        EXTI_PD = EXTI_PD_PD8;
        driver::sensor.set_raster();
    }
}
